package net.bat.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

import net.bat.db.BaseDAO;
import net.bat.pt.BObj;
import net.bat.servlet.JSonBaseServlet;

import org.hibernate.EntityMode;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.IdentifierType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import dao.hb.LSync;
import dao.hb.UUser;
/**
 * 辅助Handle的类,包含了常用方法
 * @author chen4w
 *
 */
public class HDUtil {
	final static public String DB_LOG_CN = "dao.hb.LSync";
	final static public String PN_UID = "userid";
    private static Logger LOGGER = LoggerFactory.getLogger(HDUtil.class);
	//数据库操作通用对象
	private BaseDAO dao;
	private Gson gson=new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").setPrettyPrinting().create();

	public BaseDAO getDao() {
		return dao;
	}

	public void setDao(BaseDAO dao) {
		this.dao = dao;
	}
	/**
	 * 联合查询时前缀的命名方法
	 * @param i 类名顺序
	 * @return 前缀
	 */
	static public String getPrefix(int i){
		return (char)('A'+i)+".";
	}
	/**
	 * 从object向BObj注入属性--联合查询
	 * @param ro BObj
	 * @param sos object数组
	 * @param pss 属性数组
	 */
	public void getItemValue(BObj ro,Object[] sos,String[][] pss){
		int len = Math.min(sos.length,pss.length);
		for(int i=0; i<len; i++){
			String prefix=getPrefix(i);
			getItemValue(ro,sos[i],pss[i],prefix);
		}
	}
	/**
	 * 从object向BObj注入属性
	 * @param ro BObj
	 * @param sos object数组
	 * @param pss 属性数组
	 */
	public void getItemValue(BObj ro,Object so,String[] ps,String prefix){
		if(ro.getItems()==null){
			ro.setItems(new HashMap<String,Object>());
		}
		BeanWrapper bw = new BeanWrapperImpl(so);
		for (String p : ps) {
			Object pv = bw.getPropertyValue(p);
			if(pv!=null){
				String cn = pv.getClass().getName();
				if(cn.equals("java.sql.Clob")) {
					pv = pv.toString();
				}
				if(cn.equals("java.math.BigDecimal")){
					BigDecimal fv = (BigDecimal)pv;
					pv = fv.intValue();
				}
			}
			ro.getItems().put(prefix+p, pv);
		}
	}
	
/**
 * 获取联合查询的用于新增的母体对象	
 * @param req 请求map
 * @return BObj对象
 * @throws Exception 处理过程异常,直接抛给json
 */
	public BObj getDefaultObj(HashMap<String,Object> req) throws Exception{
		String[] cns = (String[])req.get("cns");
		String[][] pss = (String[][])req.get("pss");
		String[] keys = null;
		Object ks = req.get("keys");
		if(ks!=null) {
			keys = (String[])ks;
		}
		BObj ro = new BObj();
		ro.setCns(cns);
		ro.setAction(BObj.ACTION_DEFAULT);
		for(int i=0; i<cns.length; i++){
			String prefix = getPrefix(i);
			String[] ps=pss[i];
			Object dobj;
			if(keys!=null) {
				dobj = dao.loadPO(cns[i], keys[i]);
			} else {
				dobj=dao.getDefaultObj(cns[i]);
			}
			if(cns.length>1) {
				getItemValue(ro,dobj,ps,prefix);
			} else {
				getItemValue(ro,dobj,ps,"");
			}
		}
		return ro;
	}
public void dblog(int uid,String entity,String entityId,int oper,String snap ){
	ClassMetadata cm=dao.getClassMeta(DB_LOG_CN);		
	LSync po= (LSync)cm.instantiate(null,EntityMode.POJO);
	po.setuserid(uid);
	po.setEntity(entity);
	po.setEntityId(entityId);
	po.setOper(oper);
	po.setDtCreate(new Date());
	po.setSnapJson(snap);
	dao.save(po);
	
}
static public void dblog(BaseDAO dao,int uid,String entity,String entityId,int oper,String snap ){
	ClassMetadata cm=dao.getClassMeta(DB_LOG_CN);		
	LSync po= (LSync)cm.instantiate(null,EntityMode.POJO);
	po.setuserid(uid);
	po.setEntity(entity);
	po.setEntityId(entityId);
	po.setOper(oper);
	po.setDtCreate(new Date());
	po.setSnapJson(snap);
	dao.save(po);	
}
/**
 * 根据BObj对象从数据库恢复object对象	
 * @param ro BObj对象
 * @param cn 类名
 * @param prefix 前缀
 * @return Object对象
 */
	public Object findPO(BObj ro,String cn, String prefix){
		ClassMetadata cm=dao.getClassMeta(cn);		
        String idPropName;
		//Session s;
		//s = DBHelper.getSession();
		idPropName = cm.getIdentifierPropertyName();
		//@SuppressWarnings("unused")
		//IdentifierType  it = (IdentifierType) cm.getIdentifierType();
		String key = prefix+idPropName;
		//如果items中没有包含id字段，表明此对象无需保存
		if(!ro.getItems().containsKey(key)) {
			return null;
		}
		@SuppressWarnings("unused")
		Object keyValue,kt,po=null;
		
		switch(ro.getAction()){
		case BObj.ACTION_ADD:
			po= cm.instantiate(null,EntityMode.POJO);
			break;
		case BObj.ACTION_UPDATE:
		case BObj.ACTION_REMOVE:
		case BObj.ACTION_ORIG:
			try{
				keyValue = ro.getItems().get(key);
				po = dao.loadPO(cn, keyValue.toString());
			}catch(Exception e){
			}
		}
		return po;
	}

/**
 * 根据BObj保存对象数组	
 * @param ro BObj对象
 * @param cns 类名数组
 * @param pss 属性数组
 * @return 保存之后的Object对象数组,可以获得自增主键值
 * @throws Exception 
 */
	public Object[] putItemValue(BObj ro,String[] cns,String[][] pss,UUser usr) throws Exception{
		//Session s = DBHelper.getSession();
		String prefix ="";
		int len = Math.min(cns.length,pss.length);
		Object[] pos=new Object[len];
		int posIndex=0;
		for(int i=0; i<len; i++){
			String cn = cns[i];
			ClassMetadata cm=dao.getClassMeta(cn);	
			String kpn = cm.getIdentifierPropertyName();
			if(cns.length>1) {
				prefix = getPrefix(i);
			}
			Object po = findPO(ro,cn,prefix);
			if(po==null) {
				continue;
			}
			//TODO 增加uid验证,防止firebug攻击			
			BeanWrapper bw = new BeanWrapperImpl(po);
			if(ro.getAction()==BObj.ACTION_REMOVE){
				dao.delete(po);
				pos[posIndex]=po;
				posIndex++;
				dblog(usr.getId(), cn, bw.getPropertyValue(kpn).toString(), ro.getAction(),null);
				continue;
			}
			//todo 根据值map设值而不是根据属性数组
			String[]ps = pss[i];
			ArrayList remark_list = null;
			String remark_str = null;
			if(ro.getAction()==BObj.ACTION_UPDATE){
				remark_list=new ArrayList();
			}
			
			for (String p : ps) {
				String pkey =prefix+p;
				if(bw.isWritableProperty(p) && ro.getItems().containsKey(pkey)){
					Object pv = ro.getItems().get(pkey);
/*					if(p.equals(PN_UID) ){
						Object uid = bw.getPropertyValue(PN_UID);
						if(!uid.equals(pv) && (!cns[0].equals("dao.hb.UUser") || !bw.getPropertyValue("id").equals(uid))){
							String winfo= MessageFormat.format(Cfg.info("warn.usr.attack"),usr.getId(),usr.getIpaddr());
							LOGGER.warn(winfo);
							//抛出异常
							throw new Exception(winfo);
						}
					}
*/					if(pv instanceof Boolean){
						Boolean bv = (Boolean)pv;
						pv = bv?1:0;
					}
					if(ro.getAction()==BObj.ACTION_UPDATE && !p.equals(kpn)){
						Object[] remark= new Object[]{p,bw.getPropertyValue(p),pv};
						remark_list.add(remark);
					}
					bw.setPropertyValue(p, pv);
					
				}
			}
			if(remark_list!=null){
				Object[] remarks = remark_list.toArray();
				remark_str =gson.toJson(remarks);
				
			
			}
			switch(ro.getAction()){
				case BObj.ACTION_ADD:
					//如果ACTION_ADD,不应当赋值主键属性
					bw.setPropertyValue(kpn, null);
					dao.save(po);
					dblog(usr.getId(), cn, bw.getPropertyValue(kpn).toString(), ro.getAction(),null);
					break;
				case BObj.ACTION_UPDATE:
					dao.update(po);
					dblog(usr.getId(), cn, bw.getPropertyValue(kpn).toString(), ro.getAction(),remark_str.toString());
					break;
			}
			pos[posIndex]=po;
			posIndex++;
		}
		//s.flush();
		return pos;
	}

/**
 * 根据BObj对象数组保存对象数组	
 * @param ros BObj对象数组
 * @param cns 类名数组
 * @param pss 属性数组
 * @return Object二维数组
 * @throws Exception 
 */
	public Object[][] putItemValue(BObj[] ros,String[]cns,String[][] pss,UUser usr) throws Exception{
		Object[][] rts = new Object[ros.length][cns.length];
		for(int i=0; i<ros.length; i++){
			BObj ro = ros[i];
			char action = ro.getAction();
			if(action==BObj.ACTION_DEFAULT || action==BObj.ACTION_ORIG) {
				continue;
			}
			rts[i] = putItemValue(ro,cns,pss,usr);
		}
		return rts;
	}
}



